<?php if(!defined('ROOTPATH')) die('Not define ROOTPATH');
/**
 * 自动加载器
 *
 * @author fakis738@gmail.com
 * @link http://www.woophp.com/manual/class/loader.lib.php
 * @version $id loader.lib.php v0.1 2011-12-03$
 */
class Loader
{
    var $num = 0;
	var $type = '';
	var $classes = array();
	var $node = '';
	var $path = array();
	var $path_type = array();
	var $classname = '';
	
    public function __construct($param=NULL)
    {
    	if(class_exists('WS'))
    	{
	    	$this->path 		= WS::CFG('common/var_path');
	    	$this->path_type	= WS::CFG('loader/path_type');
    	}
    }
	
	/**
	 * 自动加载类
	 * @access public
	 * @param string $node
	 * @param mix $param
	 * @return object
	 */
	public function loadClass($node, $param=NULL)
	{
		$this->loadFile($node, $param);
		
		//类名转换
		$class_name = ucfirst(str_replace('.', '_', $node));
		if(!class_exists($class_name))
			return FALSE;
		
		return new $class_name($param);
	}
	
	/**
	 * 自动加载文件
	 * @access public
	 * @param string $node
	 * @return bool
	 */
	public function loadFile($node, $param=NULL)
	{
		//字符串没有包括或者在第一个字符出现"."，视为无效
		$hex = strrpos($node, '.');
		if(empty($hex)) return FALSE;
		
		//例：single.article.lib
		//其中 $this->node = single.article, $this->type = lib
		$this->node = substr($node, 0, $hex);
		$this->type = substr($node, $hex + 1, strlen($node));
		$ext = ($this->type == 'tpl') ? 'html' : 'php';
		$this->parse($this->node, $ext);
		
		$return = FALSE;
		
		//查找并载入文件包括所有继承类文件
		foreach($this->classes as $filename)
		{
			//根据配置路径，按顺序查找对应文件
			foreach($this->path as $path)
			{
				$file = $path. $this->path_type[$this->type]. DS. $filename;
				if(is_file($file))
				{
					$return = @require_once($file);
                    if(!$return)
                    {
                        WS::ERR('自动加载文件错误');
                    }
					break;
				}
			}
		}
		return $return;
	}
	
    /**
     * 迭代所有层级继承类名，数组倒序，赋值给(array)$this->ext
     * @access protected
     * @param string $ext
     */
	protected function parse($node, $ext='php')
	{
		if(FALSE === strpos($node, '.'))
		{
			$this->classes[] = $node. '.'. $this->type. '.'. $ext;
			$this->classes = array_reverse($this->classes);
		}
		else
		{
			$this->classes[] = $node. '.'. $this->type. '.'. $ext;
			$hex = substr($node, strpos($node, '.')+1, strlen($node));
			$this->parse($hex);
		}
	}
	
    /**
     * 迭代所有层级继承类名，数组倒序，赋值给(array)$this->ext
     * @access protected
     * @param string $ext
     */
	protected function pathParser($node)
	{
		if(FALSE === strpos($node, '.'))
		{
			$this->classes[] = $node. '.'. $this->type. '.'. $this->ext;
			$this->classes = array_reverse($this->classes);
		}
		else
		{
            $classname = strtolower($this->dir. $node);
			$this->classes[] = $this->dir. $node. '.'. $this->ext;
			$hex = substr($node, strpos($node, '.')+1, strlen($node));
			$this->classParser($hex);
		}
	}

    /**
     * 路径解析器
     * @param string $path
     * @return void
     */
    public function parser($path)
    {
        if(!preg_match('/^((\w+)[\/\w+]*\/)(\w+[\.\w+]*)\.(\w+){1,4}$/', $path, $m))
        {
            WS::ERR('自动加载路径错误 path: '. $path);
        }

        $this->path = $m[0];
        $this->dir  = $m[1];
        $this->mode = $m[2];
        $this->node = $m[3];
        $this->ext  = $m[4];
    }

    /**
     * 根据路径取得类名
     * @return stirng $classname
     */
    public function getClassname()
    {
        $cls = strtolower($this->dir. $this->node);

        $arr = preg_split('/\b(\w+)\b/', $cls, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
        $classname = '';
        foreach($arr as $key => $val)
        {
            $classname .= ucfirst($val);
        }
        $classname = str_replace(array('_', '/', '.'), array('__', '_', '_To_'), $classname);

        return $classname;
    }

    public function load($path)
    {
        global $_LOAD;
        if(isset($_LOAD[$path]) && is_object($_LOAD[$path]))
        {
            $_LOAD[$path]->num++;
            return $_LOAD[$path];
        }
        $this->parser($path);
        $_LOAD[$path] = $this;
        return $_LOAD;
    }
}
